package com.gitee.huanminabc.jcommon.fastjson;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.*;
import com.alibaba.fastjson.parser.ParserConfig;
import com.gitee.huanminabc.jcommon.model.FeeRate;
import com.gitee.huanminabc.jcommon.model.Money;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;

/**
 * @description:
 * @author: huanmin
 * @create: 2025-04-17 21:46
 **/
public class FastJsonConfig {

    // 常用配置，适用于绝大多数场景对性能影响极低,
    public static void oftenUseConfig() {
        dateConfig();
        dataTypeConfig();

        // 禁止autoType（安全）
        ParserConfig.getGlobalInstance().setAutoTypeSupport(false);

        // 兼容下划线
        ParserConfig.getGlobalInstance().propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;

        /*
          默认的序列化特性配置 (给前端传输数据用的)
          1. 禁用循环引用检测 (但是如果真的有循环引用那么会导致死循环最后抛出StackOverflowError,一般在代码测试的时候就能发现所以这里就不建议开启了)
          2. 使用toString方法序列化枚举类型
          3. 忽略没有getter方法的字段
          4. 集合列表类型序列化时如果为null则序列化为空集合或者空数组
         */
//        JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteMapNullValue.getMask(); // 序列化时写入null值的字段(不建议全局设置,而是在需要的时候手动指定)
        JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();
        JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteEnumUsingToString.getMask();
        JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.IgnoreNonFieldGetter.getMask();
        JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteNullListAsEmpty.getMask();

        /*
          默认的反序列化特性配置 (给后端接收前端传输数据用的)
          <p>
          1. 允许单引号
          2. 允许注释
          3. 允许不带引号的字段名
          4. 忽略匹配不到的字段
         */
        JSON.DEFAULT_PARSER_FEATURE |= Feature.AllowSingleQuotes.getMask();
        JSON.DEFAULT_PARSER_FEATURE |= Feature.AllowComment.getMask();
        JSON.DEFAULT_PARSER_FEATURE |= Feature.AllowUnQuotedFieldNames.getMask();
        JSON.DEFAULT_PARSER_FEATURE |= Feature.IgnoreNotMatch.getMask();
    }


    public static void dateConfig() {
        // 设置全局日期格式
        SerializeConfig.getGlobalInstance().put(Date.class, new SimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss"));

        SerializeConfig.getGlobalInstance().put(
                LocalDateTime.class,
                (serializer, object, fieldName, fieldType, features) -> {
                    LocalDateTime ldt = (LocalDateTime) object;
                    String str = ldt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                    serializer.write(str);
                }
        );
        SerializeConfig.getGlobalInstance().put(
                LocalDate.class,
                (serializer, object, fieldName, fieldType, features) -> {
                    LocalDate ld = (LocalDate) object;
                    String str = ld.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                    serializer.write(str);
                }
        );

        SerializeConfig.getGlobalInstance().put(
                LocalTime.class,
                (serializer, object, fieldName, fieldType, features) -> {
                    LocalTime lt = (LocalTime) object;
                    String str = lt.format(DateTimeFormatter.ofPattern("HH:mm:ss"));
                    serializer.write(str);
                }
        );
    }

    public static void dataTypeConfig() {
        // Long类型序列化为字符串
        SerializeConfig.getGlobalInstance().put(Long.class, ToStringSerializer.instance);
        SerializeConfig.getGlobalInstance().put(Long.TYPE, ToStringSerializer.instance);
        // BigDecimal类型序列化为非科学计数法
        SerializeConfig.getGlobalInstance().put(BigDecimal.class, new BigDecimalCodec());
    }

    // Money 序列化配置
    public static void moneyConfig() {
        SerializeConfig.getGlobalInstance().put(Money.class, new MoneyObjectWriter());
        ParserConfig.getGlobalInstance().putDeserializer(Money.class, new MoneyObjectReader());
    }

    // FeeRate 序列化配置
    public static void feeRateConfig() {
        SerializeConfig.getGlobalInstance().put(FeeRate.class, new FeeRateObjectWriter());
        ParserConfig.getGlobalInstance().putDeserializer(FeeRate.class, new FeeRateObjectReader());
    }
}
